#!/usr/bin/env python
# -*- coding: utf-8 -*-

from typing import Any

from cta.interface.action.close_position.abstract_close_position_action import AbstractClosePositionAction
from web.constants.close_position_reason import ClosePositionReason
from web.constants.datetime_format import DatetimeFormat
from web.constants.direction import Direction
from web.domain.responsibility_chain_dto import ResponsibilityChainDto
from web.manager.log_manager import LogManager
from web.models import CommodityFutureInfo
from web.models.commodity_future_date_contract_data import CommodityFutureDateContractData
from web.models.quant2_account import Quant2Account
from web.models.quant2_commodity_future_filter import Quant2CommodityFutureFilter
from web.models.quant2_commodity_future_transaction_record import Quant2CommodityFutureTransactionRecord
from web.util.commodity_future_code_util import CommodityFutureCodeUtil
from web.util.datetime_util import DatetimeUtil

Logger = LogManager.get_logger(__name__)

class Quant2MultiFactorClosePositionAction(AbstractClosePositionAction):
    """
    多因子策略，平仓期货
    """

    def exec(self, responsibility_chain_dto: ResponsibilityChainDto = None) -> Any:
        Logger.info("多因子策略，平仓期货")

        transaction_date: str = responsibility_chain_dto.transaction_date

        # # 根据持仓时间，判断k线形态；判断当天是否应当平仓和开仓
        # k_line_movement_pattern, close_or_open_position = self.quant2_k_line_movement_pattern_and_close_or_open_position_by_holding_position_time(transaction_date)
        # if not close_or_open_position:
        #     Logger.info("日期[%s]不应当平仓和开仓", transaction_date)
        #     super().next(responsibility_chain_dto)
        #     return

        # 计算持仓时间
        # holding_position_date_number: int = self.quant2_commodity_future_transaction_record_dao.calculate_holding_position_date(
        #     quant2_commodity_future_transaction_record.direction, quant2_account.account_name,
        #     quant2_commodity_future_transaction_record.code)
        # if holding_position_date_number < MultiFactorConfig.Holding_Date_Number:
        #     continue
        # else:
        #     Logger.info("期货[%s]持仓时间已经到达[%s]天，品仓", quant2_commodity_future_transaction_record.code,
        #                 MultiFactorConfig.Holding_Date_Number)

        # 查询quant2_c_f_filter表的记录，并按照up_down_percentage_with_n_date列降序排列。然后创建升序数组
        long_quant2_commodity_future_filter_list: list[Quant2CommodityFutureFilter] = self.quant2_commodity_future_filter_dao.order_by_up_down_percentage_with_n_date_desc()
        if long_quant2_commodity_future_filter_list is None or len(long_quant2_commodity_future_filter_list) == 0:
            Logger.error("表quant2_c_f_filter为空，无法执行平仓操作")
            super().next(responsibility_chain_dto)
            return
        # short_quant2_commodity_future_filter_list: list[Quant2CommodityFutureFilter] = long_quant2_commodity_future_filter_list[::-1]

        # 计算多头仓位和空头仓位应该是多少
        should_long_position_number, should_short_position_number = self.calculate_long_position_and_short_position(long_quant2_commodity_future_filter_list)

        # quant2_account表的所有记录
        quant2_account_list:list[Quant2Account] = self.quant2_account_dao.find_all()
        if quant2_account_list is not None and len(quant2_account_list) > 0:

            for quant2_account_index, quant2_account in enumerate(quant2_account_list):
                # 如果这个账户没有持有期货，则查找下一个账户
                if quant2_account.hold_commodity_future_number == 0:
                    Logger.info("账号[%s]持有期货的数量为0，不需要平仓期货", quant2_account.account_name)
                    continue

                # 应该持有的多头和空头期货
                should_long_quant2_commodity_future_filter_list, should_short_quant2_commodity_future_filter_list = self.find_should_hold_long_and_short_commodity_future_filter_list(quant2_account_index, should_long_position_number, should_short_position_number)

                # 查询实际持仓期货中多头数量
                # actual_long_position_number: int = self.find_quant2_actual_long_position_number(quant2_account.account_name, Direction.Up)

                # 查询实际持仓期货中空头数量
                # actual_short_position_number: int = self.find_quant2_actual_short_position_number(quant2_account.account_name, Direction.Down)

                # 某个量化账户的持仓的期货的交易记录
                quant2_commodity_future_transaction_record_list:list[Quant2CommodityFutureTransactionRecord] = self.quant2_commodity_future_transaction_record_dao.find_by_account_name_and_not_close_position(quant2_account.account_name)
                if quant2_commodity_future_transaction_record_list is not None and len(quant2_commodity_future_transaction_record_list) > 0:

                    # 平仓
                    for quant2_commodity_future_transaction_record in quant2_commodity_future_transaction_record_list:

                        # 如果当前实际持仓的期货也是应该持仓的期货，则跳过
                        if quant2_commodity_future_transaction_record.direction == Direction.Up and should_long_quant2_commodity_future_filter_list is not None \
                                and quant2_commodity_future_transaction_record.code in list(map(lambda x: x.code, should_long_quant2_commodity_future_filter_list)):
                            continue
                        if quant2_commodity_future_transaction_record.direction == Direction.Down and should_short_quant2_commodity_future_filter_list is not None \
                                and quant2_commodity_future_transaction_record.code in list(map(lambda x: x.code, should_short_quant2_commodity_future_filter_list)):
                            continue

                        # 查询期货
                        commodity_future_date_contract_data: CommodityFutureDateContractData = self.commodity_future_date_contract_data_dao.find_by_code_and_transaction_date(quant2_commodity_future_transaction_record.code, transaction_date)
                        if commodity_future_date_contract_data is None:
                            Logger.warning("期货[%s]在日期[%s]没有交易记录，所以跳过", quant2_commodity_future_transaction_record.code, transaction_date)
                            continue

                        # 根据持仓时间，判断k线形态；判断当天是否应当平仓和开仓
                        k_line_movement_pattern, close_or_open_position = self.quant2_k_line_movement_pattern_and_close_or_open_position_by_holding_position_time_and_commodity_future_date_contract_data(transaction_date, commodity_future_date_contract_data)
                        if close_or_open_position is False:
                            Logger.info("期货[%s]在日期[%s]不应当平仓和开仓", commodity_future_date_contract_data.code, transaction_date)
                            continue

                        # 查询commodity_future_info记录
                        filter_dict = {'code__iexact': CommodityFutureCodeUtil.code_to_contract_code(commodity_future_date_contract_data.code)}
                        commodity_future_info: CommodityFutureInfo = self.commodity_future_info_dao.find_one(filter_dict, dict(), list())

                        # 更新quant2_c_f_transact_record表的sell_date/buy_date、sell_price/buy_price、sell_lot/buy_lot、profit_and_loss和profit_and_loss_rate字段
                        self.quant2_commodity_future_transaction_record_dao.update_when_close_position(quant2_commodity_future_transaction_record.direction, transaction_date,
                                                                                                       commodity_future_date_contract_data.close_price, commodity_future_info,
                                                                                                       quant2_commodity_future_transaction_record.buy_lot if quant2_commodity_future_transaction_record.direction == Direction.Up else quant2_commodity_future_transaction_record.sell_lot,
                                                                                                       ClosePositionReason.Multi_Factor_Close_Position, quant2_commodity_future_transaction_record.id_)
                else:
                    Logger.warning("账号[%s]没有持仓记录", quant2_account.account_name)
        else:
            Logger.warning("表quant2_account没有记录")

        super().next(responsibility_chain_dto)